package cn.kow.kmall.security;

import cn.kow.kmall.core.util.JwtTokenUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Author: lijun
 * @Description:
 * @Date: Created in 2019-10-31 11:39
 * @Modified By:
 */
@Slf4j
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    private UserDetailsService userDetailsService;

    private AuthenticationFailureHandler authenticationFailureHandler;

    private String secret;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        AuthenticationException exception = null;
        try {
            log.info("doFilterInternal url=" + request.getRequestURI());
            String token = getRequestToken(request);
            if (StringUtils.isEmpty(token)) {
                throw new InsufficientAuthenticationException("TOKEN IS EMPTY");
            }
            // 校验token
            Claims claims = JwtTokenUtils.verify(token, secret);
            String username = claims.get("username").toString();
            UserDetails sysUser = userDetailsService.loadUserByUsername(username);
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, sysUser.getPassword(), sysUser.getAuthorities());
            authentication.setDetails(new WebAuthenticationDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authentication);
            request.setAttribute("user", sysUser);
        } catch (AuthenticationException e) {
            exception = e;
        } catch (Exception ex) {
            exception = new AccountExpiredException(ex.getMessage());
        }

        if (exception != null){
            authenticationFailureHandler.onAuthenticationFailure(request, response, exception);
            return;
        }
        filterChain.doFilter(request, response);
    }


    /**
     * 获取请求的token
     */
    private String getRequestToken(HttpServletRequest request) {
        String auth = request.getHeader("Authorization");
        String token = StringUtils.removeStart(auth, "Bearer ");
        return token;
    }

    public void setSecret(String secret) {
        this.secret = secret;
    }

    public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
        this.authenticationFailureHandler = failureHandler;
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

}
